package model;

import java.util.ArrayList;

import android.os.CountDownTimer;
import controller.EndGameObserver;
import controller.GridPicturesObserver;
import controller.InfoBarObserver;
import controller.LevelNameObserver;
import controller.PauseObserver;

public class GameModel implements GameModelInterface {
	private LevelModel _level;

	private int _mode = READY;
	public static final int PAUSE = 0;
	public static final int READY = 1;
	public static final int RUNNING = 2;

	private int _life;
	private int _score;
	private int _time;

	private long _durationPicture;
	private CountDownTimer _countDownTimerPicture;

	private long _durationLevel;
	private CountDownTimer _countDownTimerLevel;

	ArrayList<InfoBarObserver> _infoBarObservers = new ArrayList<InfoBarObserver>();
	ArrayList<LevelNameObserver> _levelNameObserver = new ArrayList<LevelNameObserver>();
	ArrayList<GridPicturesObserver> _gridPicturesObserver = new ArrayList<GridPicturesObserver>();
	ArrayList<EndGameObserver> _endGameObserver = new ArrayList<EndGameObserver>();
	ArrayList<PauseObserver> _pauseObserver = new ArrayList<PauseObserver>();

	private boolean _hasEndedGame = false;

	public GameModel(LevelModel level) {
		this._hasEndedGame = false;
		this._mode = READY;
		this._level = level;
		GameManager gameManager = GameManager.getInstance();
		this._life = gameManager.getLife();
		this._score = gameManager.getScore();

		this._time = (int) level.getDurationLevel() / 1000;

		_durationPicture = this._level.getDurationPicture();
		_durationLevel = this._level.getDurationLevel();

		this._level.shufflePictures();
		pause();
	}

	public LevelModel getLevel() {
		return _level;
	}

	public int getLife() {
		return this._life;
	}

	public Integer[] getPictures() {
		return _level.getPictures();
	}

	public int getScore() {
		return this._score;
	}

	public int getTime() {
		return this._time;
	}

	public void nextStepPicture() {
		_durationPicture = _level.getDurationPicture();
		_countDownTimerPicture.start();

		_level.shufflePictures();
		update();
	}

	public void notifyEndGameObserver(String levelName, int score) {
		if (!_hasEndedGame) {
			for (int i = 0; i < _endGameObserver.size(); i++) {
				EndGameObserver observer = (EndGameObserver) _endGameObserver
						.get(i);
				observer.updateToEndGame(levelName, score);
			}
		}
		_hasEndedGame = true;
	}

	public void notifyGridPicturesObserver(Integer[] pictures,
			Integer[] visibles) {
		for (int i = 0; i < _gridPicturesObserver.size(); i++) {
			GridPicturesObserver observer = (GridPicturesObserver) _gridPicturesObserver
					.get(i);
			observer.updateGridPictures(pictures, visibles);
		}
	}

	public void notifyInfoBarObserver(int life, int score, int time) {
		for (int i = 0; i < _infoBarObservers.size(); i++) {
			InfoBarObserver observer = (InfoBarObserver) _infoBarObservers
					.get(i);
			observer.updateInfoBar(life, score, time);
		}
	}

	public void notifyPauseObserver(String levelName, int life, int score,
			int time) {
		for (int i = 0; i < _infoBarObservers.size(); i++) {
			PauseObserver observer = (PauseObserver) _infoBarObservers.get(i);
			observer.updateToPause(levelName, score, time, life);
		}
	}

	public void notifyLevelNameObserver(String name) {
		for (int i = 0; i < _levelNameObserver.size(); i++) {
			LevelNameObserver observer = (LevelNameObserver) _levelNameObserver
					.get(i);
			observer.updateLevelName(name);
		}
	}

	public void pause() {
		if (PAUSE != _mode || READY == _mode) {
			notifyPauseObserver(_level.getName(), _life, _score, _time);
		}
		setMode(PAUSE);
	}

	// Observer du nom du niveau
	public void registerObserver(EndGameObserver observer) {
		_endGameObserver.add(observer);
	}

	// Observer des images
	public void registerObserver(GridPicturesObserver observer) {
		_gridPicturesObserver.add(observer);
	}

	// Observer des infos
	public void registerObserver(InfoBarObserver observer) {
		_infoBarObservers.add(observer);
	}

	// Observer du nom du niveau
	public void registerObserver(LevelNameObserver observer) {
		_levelNameObserver.add(observer);
	}

	private void removeLife() {
		_life -= _level.getLifeByMissedPicture();
		if (0 >= _life) {
			_life = 0;
			lose();
		}
	}

	public void removeObserver(EndGameObserver observer) {
		int index = _endGameObserver.indexOf(observer);
		if (index >= 0)
			_endGameObserver.remove(index);

	}

	public void removeObserver(GridPicturesObserver observer) {
		int index = _gridPicturesObserver.indexOf(observer);
		if (index >= 0)
			_gridPicturesObserver.remove(index);
	}

	public void removeObserver(InfoBarObserver observer) {
		int index = _infoBarObservers.indexOf(observer);
		if (index >= 0)
			_infoBarObservers.remove(index);
	}

	public void removeObserver(LevelNameObserver observer) {
		int index = _levelNameObserver.indexOf(observer);
		if (index >= 0)
			_levelNameObserver.remove(index);
	}

	public void start() {
		notifyLevelNameObserver(_level.getName());
		update();
		setMode(RUNNING);
	}

	public void touch(int position) {
		if (_level.touch(position)) {
			nextStepPicture();
			_score += _level.getScoreByPicture();
		} else {
			removeLife();
			update();
		}
	}

	public void update() {
		notifyInfoBarObserver(_life, _score, _time);
		notifyGridPicturesObserver(_level.getPictures(), _level.getVisibles());
	}

	public void win() {
		setMode(PAUSE);
		_time = 0;
		update();
		try {
			Thread.sleep(500);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		GameManager gameManager = GameManager.getInstance();
		gameManager.setScore(gameManager.getScore() + _score);
		gameManager.setLife(_life);
		gameManager.setNextLevelIndex();
		gameManager.start(gameManager.getActivity());
	}

	public void lose() {
		setMode(PAUSE);
		update();
		notifyEndGameObserver(_level.getName(), _score);
	}

	private void stopCountDownTimer() {
		if (null != _countDownTimerLevel) {
			_countDownTimerLevel.cancel();
		}
		if (null != _countDownTimerPicture) {
			_countDownTimerPicture.cancel();
		}
	}

	private void startCountDownTimer() {
		_countDownTimerLevel = new CountDownTimer(_durationLevel, 1000) {
			@Override
			public void onFinish() {
				win();
			}

			@Override
			public void onTick(long millisUntilFinished) {
				_time = (int) (_durationLevel / 1000);
				_durationLevel = millisUntilFinished;
				update();
			}
		};
		_countDownTimerLevel.start();

		_countDownTimerPicture = new CountDownTimer(_durationPicture, 80) {
			@Override
			public void onFinish() {
				removeLife();
				nextStepPicture();
			}

			@Override
			public void onTick(long millisUntilFinished) {
				_durationPicture = millisUntilFinished;
			}
		};
		_countDownTimerPicture.start();
	}

	private void setMode(int mode) {
		// Log.e("GameModel", "setMode _mode=" + _mode + " mode=" + mode);

		if ((READY == this._mode || PAUSE == this._mode) && RUNNING == mode) {
			startCountDownTimer();
		}

		if (PAUSE == mode) {
			stopCountDownTimer();
		}
		this._mode = mode;
	}

	public void registerObserver(PauseObserver observer) {
		_pauseObserver.add(observer);
	}

	public void removeObserver(PauseObserver observer) {
		int index = _pauseObserver.indexOf(observer);
		if (index >= 0)
			_pauseObserver.remove(index);
	}
}
